home *** CD-ROM | disk | FTP | other *** search
/ Internet Surfer: Getting Started / Internet Surfer - Getting Started (Wayzata Technology)(7231)(1995).bin / pc / mac / bonus / peter_le / dehqx-20 / readhqx.p < prev    next >
Text File  |  1991-08-23  |  13KB  |  558 lines

  1. unit ReadHQX;
  2. { DeHQX v2.0.0 ⌐ Peter Lewis, Aug 1991 }
  3.  
  4. interface
  5.  
  6.     uses
  7.         MyTypes, MyFileSystem, AppGlobals, MyUtilities, CRCs, Preferences, Displays, HQXLists, MyMainLoop, SmallEvents;
  8.  
  9.     type
  10.         hqxInfo = record
  11.                 name: str63;
  12.                 wdrn: integer;
  13.                 dirID: longInt;
  14.                 c, t: OSType;
  15.                 flags: integer;
  16.                 dlen, rlen: longInt;
  17.             end;
  18.  
  19.     var
  20.         crc: integer;
  21.  
  22.     procedure InitReadHQX;
  23.     procedure FinishReadHQX;
  24.     procedure ReInitReadHQX;
  25.     function OpenHQX: OSErr;
  26.     procedure FinishHQX;
  27.     procedure CreateFolder (var ovrn: integer; var odirID: longInt);
  28.     function ReadByte (var b: byte): OSErr;
  29.     function ReadColon: OSErr;
  30.     function ReadInteger (var b: integer): OSErr;
  31.     function ReadLong (var b: longInt): OSErr;
  32.     function ReadOSType (var t: OSType): OSErr;
  33.     function ReadString (var s: str255): OSErr;
  34.     function ReadHeader (var hi: hqxInfo; wp: windowPtr): OSErr;
  35.  
  36. implementation
  37.  
  38.     const
  39.         buffer_slop = 70;        { Amount of lookahead required to scan for beginstr }
  40.         buffer_size = 16384;
  41.         dud_byte = 255;
  42.         cr = 13;
  43.         lf = 10;
  44.         spc = 32;
  45.         bad_filern = -32000;
  46.  
  47.     var
  48.         thevalue: packed array[0..255] of byte;
  49.         state: 0..6;
  50.         value: byte;
  51.         repeating: boolean;
  52.         repvalue: byte;
  53.         repcount: integer;
  54.         startstr, beginstr: str63;
  55.         blen: integer;        { blen=length(beginstr) }
  56.         read_hqx_byte: longInt;  { incremented for each read hqx byte, if it exceeds buffer_slop }
  57. { I will accept the file for deletion. }
  58.         infile: integer;
  59.         buffer: packed array[0..buffer_size] of byte;
  60.         buffer_len: integer;
  61.         finished_files: boolean;
  62.         default_ovrn: integer;
  63.         default_odirID: longInt;
  64.         create_folder: boolean;
  65.  
  66.     procedure CreateFolder (var ovrn: integer; var odirID: longInt);
  67.         var
  68.             oe: OSErr;
  69.             pb: CInfoPBRec;
  70.             dirID: longInt;
  71.             s: str255;
  72.     begin
  73.         ovrn := default_ovrn;
  74.         odirID := default_odirID;
  75.         if create_folder then begin
  76.             oe := DirCreate(ovrn, odirID, GetGlobalString(folder_name), dirID);
  77.             if oe <> noErr then begin
  78.                 with pb do begin
  79.                     s := GetGlobalString(folder_name);
  80.                     ioNamePtr := @s;
  81.                     ioVRefNum := ovrn;
  82.                     ioFDirIndex := 0;
  83.                     ioDirID := odirID;
  84.                     oe := PBGetCatInfo(@pb, false);
  85.                     if oe = noErr then begin
  86.                         if BAND(ioFlAttrib, $0010) <> 0 then begin
  87.                             odirID := ioDirID;
  88.                         end;
  89.                     end;
  90.                 end;
  91.             end
  92.             else
  93.                 odirID := dirID;
  94.             default_odirID := odirID;
  95.             create_folder := false;
  96.         end;
  97.     end;
  98.  
  99.     procedure InitReadHQX;
  100.         var
  101.             i: integer;
  102.             s: str255;
  103.     begin
  104.         GetIndString(s, hqx_strh_id, 3);
  105.         for i := 0 to 255 do
  106.             thevalue[i] := dud_byte;
  107.         for i := 1 to 64 do begin
  108.             thevalue[ord(s[i])] := i - 1;
  109.         end;
  110.         startstr := GetIndStrSize(sizeof(startstr), hqx_strh_id, 1);
  111.         beginstr := GetIndStrSize(sizeof(beginstr), hqx_strh_id, 2);
  112.         blen := length(beginstr) - 1;
  113.         InitHQXLists;
  114.     end;
  115.  
  116.     procedure ReInitReadHQX;
  117.     begin
  118.         state := 0;
  119.         value := 0;
  120.         repeating := false;
  121.         repcount := 0;
  122.     end;
  123.  
  124.     procedure FinishReadHQX;
  125.     begin
  126.         FinishHQXLists;
  127.     end;
  128.  
  129.     function ReadBuffer: OSErr;
  130. { NOTE: must have  buffer_len-buffer_slop<=buffer_pos<=buffer_len }
  131.         var
  132.             bl: longInt;
  133.             oe: OSErr;
  134.             bs: integer;
  135.     begin
  136.         if (buffer_pos = 0) and (buffer_len = buffer_size) then
  137.             oe := myErr
  138.         else begin
  139.             bs := buffer_len - buffer_pos;
  140.             if bs > 0 then
  141.                 BlockMove(@buffer[buffer_pos], @buffer[0], bs);
  142.             size_processed := size_processed + buffer_pos;
  143.             buffer_pos := 0;
  144.             bl := buffer_size - bs;
  145.             oe := FSRead(infile, bl, @buffer[bs]);
  146.             if oe = eofErr then
  147.                 oe := noErr;
  148.             if bl = 0 then
  149.                 oe := eofErr;
  150.             if oe <> noErr then
  151.                 bl := 0;
  152.             buffer_len := bl + bs;
  153.         end;
  154.         ReadBuffer := oe;
  155.     end;
  156.  
  157.     function OpenEitherHQX: OSErr;
  158.         var
  159.             oe, ooe: OSErr;
  160.             dirID: longInt;
  161.             name: str63;
  162.     begin
  163.         if AnyFilesLeft then begin
  164.             GetNextFile(default_ovrn, default_odirID, name, create_folder);
  165.             oe := MFSOpenDF(infile, default_ovrn, default_odirID, name, PIn);
  166.             if oe = noErr then
  167.                 oe := ReadBuffer
  168.             else
  169.                 infile := bad_filern;
  170.             read_hqx_byte := 0;
  171.         end
  172.         else
  173.             oe := fnfErr;
  174.         OpenEitherHQX := oe;
  175.     end;
  176.  
  177.     function OpenHQX: OSErr;
  178.     begin
  179.         buffer_len := 1;
  180.         buffer_pos := 1;
  181.         finished_files := false;
  182.         OpenHQX := OpenEitherHQX
  183.     end;
  184.  
  185.     function OpenOtherHQX: OSErr;
  186.         var
  187.             ooe: OSErr;
  188.     begin
  189.         if infile <> bad_filern then begin
  190.             ooe := FSClose(infile);
  191.             infile := bad_filern;
  192.             FinishFile(read_hqx_byte > buffer_slop);
  193. { yick.  Its the only way I figure I can safely delete a file, given all the buffering going on }
  194.         end;
  195.         OpenOtherHQX := OpenEitherHQX;
  196.     end;
  197.  
  198.     procedure FinishHQX;
  199.         var
  200.             ooe: OSErr;
  201.     begin
  202.         if infile <> bad_filern then
  203.             ooe := FSClose(infile);
  204.     end;
  205.  
  206.     function FileReadByte (var b: byte): OSErr;
  207.         var
  208.             oe: OSErr;
  209.     begin  { Some of this code is expanded inline in other procedures, so be careful modifying it }
  210.         if buffer_pos < buffer_len - buffer_slop then begin
  211.             b := buffer[buffer_pos];
  212.             buffer_pos := buffer_pos + 1;
  213.             FileReadByte := noErr;
  214.         end
  215.         else begin
  216.             oe := noErr;
  217.             if finished_files then begin
  218.                 if buffer_pos >= buffer_len then
  219.                     oe := fnfErr;
  220.             end
  221.             else begin
  222.                 while (buffer_pos >= buffer_len - buffer_slop) and (oe = noErr) do
  223.                     oe := ReadBuffer;
  224.                 while oe = eofErr do
  225.                     oe := OpenOtherHQX;
  226.                 if oe = fnfErr then begin
  227.                     if buffer_pos < buffer_len then
  228.                         oe := noErr;
  229.                     finished_files := true;
  230.                 end;
  231.             end;
  232.             if oe = noErr then begin
  233.                 b := buffer[buffer_pos];
  234.                 buffer_pos := buffer_pos + 1;
  235.             end;
  236.             FileReadByte := oe;
  237.         end;
  238.     end;
  239.  
  240.     function ReadAByte (var b: byte): OSErr;
  241.         var
  242.             oe: OSErr;
  243.             i: integer;
  244.         procedure RB;
  245.             var
  246.                 b: byte;
  247.             label
  248.                 1;
  249.         begin
  250.             if buffer_pos < buffer_len - buffer_slop then begin
  251.                 b := buffer[buffer_pos];
  252.                 buffer_pos := buffer_pos + 1;
  253.                 oe := noErr;
  254.                 if b <= spc then
  255.                     goto 1;
  256.                 value := thevalue[b];
  257.                 if value = dud_byte then
  258.                     oe := HqxFormatErr;
  259.             end
  260.             else begin
  261.                 oe := FileReadByte(b);
  262. 1:        { skip <cr>, and check for <cr>--- end of part }
  263.                 if b <= spc then {short cut most of this expression for the normal case }
  264.                     if oe = noErr then begin
  265.                         while (oe = noErr) and (b <= spc) do
  266.                             oe := FileReadByte(b);
  267.                         if b = ord(beginstr[1]) then
  268.                             if prefs.parts_state then
  269.                                 if (buffer[buffer_pos] = ord(beginstr[2])) and (buffer_pos + blen - 2 <= buffer_len) then begin
  270.                                     i := 3;
  271.                                     while (buffer[buffer_pos + i - 2] = ord(beginstr[i])) and (i < blen) do begin
  272.                                         i := i + 1;
  273.                                     end;
  274.                                     if i = blen then begin {skiping headers - waiting for a <cr>---<cr> }
  275.                                         buffer_pos := buffer_pos + i - 2;
  276.                                         repeat
  277.                                             repeat
  278.                                                 while (oe = noErr) and (b >= spc) do
  279.                                                     oe := FileReadByte(b);
  280.                                                 while (oe = noErr) and (b < spc) do
  281.                                                     oe := FileReadByte(b);
  282.                                             until (oe <> noErr) or (b = ord('-'));
  283.                                         until (oe <> noErr) or ((buffer[buffer_pos] = b) and (buffer[buffer_pos + 1] = b) and (buffer[buffer_pos + 2] <= spc));
  284.                                         if oe = noErr then
  285.                                             oe := FileReadByte(b);  { '-' }
  286.                                         if oe = noErr then
  287.                                             oe := FileReadByte(b);  { '-' }
  288.                                         if oe = noErr then
  289.                                             oe := FileReadByte(b);  { cr }
  290.                                         if oe = noErr then
  291.                                             oe := FileReadByte(b);  { next char }
  292.                                         if oe = noErr then
  293.                                             goto 1;
  294.                                     end; { if i=blen }
  295.                                 end; { if parts_state }
  296.                     end; { if b<=spc }
  297.                 if oe = noErr then begin
  298.                     value := thevalue[b];
  299.                     if value = dud_byte then
  300.                         oe := HqxFormatErr;
  301.                 end;
  302.             end;
  303.         end;
  304.     begin
  305.         case state of
  306.             0: 
  307.                 begin
  308.                 RB;
  309.                 b := BAND(BSL(value, 2), $FF);
  310.                 if oe = noErr then
  311.                     RB;
  312.                 b := BOR(b, BSR(value, 4));
  313.                 state := 2;
  314.             end;
  315.             2: 
  316.                 begin
  317.                 b := BAND(BSL(value, 4), $FF);
  318.                 RB;
  319.                 b := BOR(b, BSR(value, 2));
  320.                 state := 4;
  321.             end;
  322.             4: 
  323.                 begin
  324.                 b := BAND(BSL(value, 6), $FF);
  325.                 RB;
  326.                 b := BOR(b, value);
  327.                 state := 0;
  328.             end;
  329.             otherwise
  330.                 oe := myErr;
  331.         end;
  332.         ReadAByte := oe;
  333.     end;
  334.  
  335.     function ReadByte (var b: byte): OSErr;
  336.         label
  337.             1;
  338.         var
  339.             oe: OSErr;
  340.     begin
  341.         if repeating then begin
  342.             oe := noErr;
  343.             repcount := repcount - 1;
  344.             repeating := repcount > 0;
  345.             b := repvalue;
  346.         end
  347.         else begin
  348. 1:
  349.             oe := ReadAByte(b);
  350.             if b = $90 then
  351.                 if oe = noErr then begin
  352.                     oe := ReadAByte(b);
  353.                     if oe = noErr then
  354.                         if b = 0 then
  355.                             b := $90
  356.                         else begin
  357.                             if b < 2 then
  358.                                 goto 1;
  359.                             repcount := b - 2;
  360.                             repeating := repcount > 0;
  361.                             b := repvalue;
  362.                         end;
  363.                 end;
  364.         end;
  365.         CalcCRC(crc, b);
  366.         read_hqx_byte := read_hqx_byte + 1;
  367.         repvalue := b;
  368.         ReadByte := oe;
  369.     end;
  370.  
  371.     function ReadColon: OSErr;
  372.         var
  373.             b: byte;
  374.             oe: OSErr;
  375.     begin
  376.         oe := FileReadByte(b);
  377.         if (oe = noErr) and (b = ord('!')) then         { slight kludge, beets me why! }
  378.             oe := FileReadByte(b);
  379.         if (oe = noErr) and (b <> ord(':')) then
  380.             oe := hqxFormatErr;
  381.         ReadColon := oe;
  382.     end;
  383.  
  384. {$PUSH}
  385. {$R-}
  386.     function ReadInteger (var b: integer): OSErr;
  387.         var
  388.             b1, b2: byte;
  389.             oe: OSErr;
  390.     begin
  391.         oe := ReadByte(b1);
  392.         if oe = noErr then
  393.             oe := ReadByte(b2);
  394.         if oe = noErr then
  395.             b := BOR(BSL(b1, 8), b2);
  396.         ReadInteger := oe;
  397.     end;
  398.  
  399.     function ReadLong (var b: longInt): OSErr;
  400.         var
  401.             b1, b2, b3, b4: byte;
  402.             oe: OSErr;
  403.     begin
  404.         oe := ReadByte(b1);
  405.         if oe = noErr then
  406.             oe := ReadByte(b2);
  407.         if oe = noErr then
  408.             oe := ReadByte(b3);
  409.         if oe = noErr then
  410.             oe := ReadByte(b4);
  411.         if oe = noErr then
  412.             b := BOR(BOR(BOR(BSL(b1, 24), BSL(b2, 16)), BSL(b3, 8)), b4);
  413.         ReadLong := oe;
  414.     end;
  415. {$POP}
  416.  
  417.     function ReadOSType (var t: OSType): OSErr;
  418.     begin
  419.         ReadOSType := ReadLong(longInt(t));
  420.     end;
  421.  
  422.     function ReadString (var s: str255): OSErr;
  423.         var
  424.             oe: OSErr;
  425.             len, ch: byte;
  426.     begin
  427.         oe := ReadByte(len);
  428.         s := '';
  429.         while (oe = noErr) and (len > 0) do begin
  430.             oe := ReadByte(ch);
  431.             s := concat(s, chr(ch));
  432.             len := len - 1;
  433.         end;
  434.         ReadString := oe;
  435.     end;
  436.  
  437.     function FindStart (wp: windowPtr): OSErr;
  438.         var
  439.             oe: OSErr;
  440.             b: byte;
  441.             dummy_reply: HEReply;
  442.             slen, i, cnt: integer;
  443.             startchar: byte;
  444.     begin
  445.         slen := length(startstr);
  446.         startchar := ord(startstr[1]);
  447.         cnt := 1;
  448.         oe := noErr;
  449.         while (oe = noErr) do begin
  450.             repeat
  451.                 if buffer_pos < buffer_len - buffer_slop then begin
  452.                     b := buffer[buffer_pos];
  453.                     buffer_pos := buffer_pos + 1;
  454.                 end
  455.                 else begin
  456.                     oe := FileReadByte(b);
  457.                     if oe <> noErr then begin
  458.                         FindStart := oe;
  459.                         exit(FindStart);
  460.                     end;
  461.                 end;
  462.                 cnt := cnt - 1;
  463.                 if cnt < 1 then begin
  464.                     DisplayUpdate(wp);
  465.                     cnt := 1024;
  466.                     HandleCancelErrorEvents(0, nil, oe, dummy_reply);
  467.                     if oe <> noErr then begin
  468.                         FindStart := oe;
  469.                         exit(FindStart);
  470.                     end;
  471.                 end;
  472.             until (b = startchar) or (b = ord(':'));
  473.             if (b = startchar) and (buffer_len >= buffer_pos + slen) then begin
  474.                 i := 2;
  475.                 while (buffer[buffer_pos + i - 2] = ord(startstr[i])) and (i < slen) do begin
  476.                     i := i + 1;
  477.                 end;
  478.                 if i = slen then begin
  479.                     buffer_pos := buffer_pos + i - 2;
  480.                     oe := FileReadByte(b);
  481.                     while (oe = noErr) and (b >= spc) do
  482.                         oe := FileReadByte(b);
  483.                     while (oe = noErr) and (b <= spc) do
  484.                         oe := FileReadByte(b);
  485.                     if (oe <> noErr) or (b = ord(':')) then begin
  486.                         FindStart := oe;
  487.                         exit(FindStart);
  488.                     end;
  489.                 end
  490.             end
  491.             else if not prefs.demand_thisfile_state and (buffer_len >= buffer_pos + 64) then
  492.                 if (b = ord(':')) and (buffer[buffer_pos + 63] < spc) then begin
  493.                     i := 0;
  494.                     while (thevalue[buffer[buffer_pos + i]] <> dud_byte) and (i < 63) do begin
  495.                         i := i + 1;
  496.                     end;
  497.                     if (i = 63) then begin
  498.                         FindStart := oe;
  499.                         exit(FindStart);
  500.                     end;
  501.                 end;
  502.         end;
  503.         FindStart := oe;
  504.     end;
  505.  
  506.     function ReadHeader (var hi: hqxInfo; wp: windowPtr): OSErr;
  507.         var
  508.             oe: OSErr;
  509.             b: byte;
  510.             hc: integer;
  511.             actcrc: integer;
  512.             nam: str255;
  513.             i: integer;
  514.     begin
  515.         with hi do begin
  516.             ReInitReadHQX;
  517.             oe := FindStart(wp);
  518.             crc := 0;
  519.             if oe = noErr then
  520.                 oe := ReadString(nam);
  521.             if (oe = noErr) and ((length(nam) > 63) or (length(nam) < 1)) then
  522.                 oe := HqxFormatErr;                        { certainly not a proper HQX file }
  523.             if oe = noErr then begin
  524.                 name := nam;
  525.                 if name[1] = '.' then
  526.                     name[1] := 'Ñ';    { Don't create files with names starting with '.' }
  527.                 for i := 1 to length(name) do begin
  528.                     if name[i] = ':' then
  529.                         name[i] := '-';
  530.                 end;
  531.             end;
  532.             if oe = noErr then
  533.                 oe := ReadByte(b);
  534.             if (oe = noErr) and (b <> 0) then
  535.                 oe := HqxFormatErr;
  536.             if oe = noErr then
  537.                 oe := ReadOSType(t);
  538.             if oe = noErr then
  539.                 oe := ReadOSType(c);
  540.             if oe = noErr then
  541.                 oe := ReadInteger(flags);
  542.             if oe = noErr then
  543.                 oe := ReadLong(dlen);
  544.             if oe = noErr then
  545.                 oe := ReadLong(rlen);
  546.             if oe = noErr then begin
  547.                 CalcCRC(crc, 0);
  548.                 CalcCRC(crc, 0);
  549.                 actcrc := crc;
  550.                 oe := ReadInteger(hc);
  551.                 if (actcrc <> hc) and (oe = noErr) then
  552.                     oe := HqxFormatErr;
  553.             end;
  554.         end;
  555.         ReadHeader := oe;
  556.     end;
  557.  
  558. end.